Õppige nullist looma turvalist ja robustset kasutajate sisselogimissüsteemi Flaskis. See põhjalik juhend käsitleb projekti seadistamist, paroolide räsimist, seansihaldust ja täiustatud turvameetmeid.
Flaski Autentimine: Põhjalik Juhend Turvaliste Kasutajate Sisselogimissüsteemide Ehitamiseks
Tänapäeva digitaalses maailmas vajab peaaegu iga sisukas veebirakendus viisi oma kasutajate haldamiseks ja tuvastamiseks. Olenemata sellest, kas ehitate sotsiaalvõrgustikku, e-kaubanduse platvormi või ettevõtte siseveebi, pole turvaline ja usaldusväärne autentimissüsteem pelgalt funktsioon – see on fundamentaalne nõue. See on digitaalne väravavaht, mis kaitseb kasutajaandmeid, isikupärastab kogemusi ja loob usaldust.
Flask, populaarne Pythoni mikroraamistik, pakub paindlikkust võimsate veebirakenduste loomiseks, kuid jätab autentimise implementeerimise teadlikult arendaja hooleks. See minimalistlik lähenemine on tugevus, mis võimaldab teil valida töö jaoks parimad vahendid, ilma et oleksite seotud konkreetse metoodikaga. Samas tähendab see ka, et vastutate süsteemi korrektse ja turvalise ehitamise eest.
See põhjalik juhend on mõeldud rahvusvahelisele arendajate kogukonnale. Juhendame teid samm-sammult läbi täieliku, tootmisvalmis kasutajate sisselogimissüsteemi ehitamise protsessi Flaskis. Alustame absoluutsetest alustest ja liigume järk-järgult robustse lahenduse poole, käsitledes teel olulisi turvameetmeid. Selle õpetuse lõpuks on teil teadmised ja kood, et implementeerida turvaline kasutajate registreerimine, sisselogimine ja seansihaldus omaenda Flasi projektides.
Eeltingimused: Arenduskeskkonna Seadistamine
Enne kui kirjutame oma esimese rea autentimiskoodi, peame looma puhta ja organiseeritud arenduskeskkonna. See on tarkvaraarenduses universaalne parim praktika, mis tagab, et teie projekti sõltuvused ei satu konflikti teiste teie süsteemis olevate projektidega.
1. Python ja Virtuaalkeskkonnad
Veenduge, et teie süsteemi on installitud Python 3.6 või uuem versioon. Kasutame virtuaalkeskkonda, et isoleerida meie projekti paketid. Avage oma terminal või käsurida ja käivitage järgmised käsud:
# Loo projekti kaust
mkdir flask-auth-project
cd flask-auth-project
# Loo virtuaalkeskkond ('venv' kaust)
python3 -m venv venv
# Aktiveeri virtuaalkeskkond
# macOS/Linux:
source venv/bin/activate
# Windows:
venv\Scripts\activate
Teate, et keskkond on aktiivne, kui näete oma käsurea ees prefiksit `(venv)`.
2. Oluliste Flasi Laienduste Installimine
Meie autentimissüsteem ehitatakse suurepäraste, hästi hooldatud Flasi laienduste abil. Igaüks neist täidab kindlat eesmärki:
- Flask: Põhiline veebiraamistik.
- Flask-SQLAlchemy: Objekt-relatsiooniline kaardistaja (ORM) meie andmebaasiga Pythoni-päraseks suhtlemiseks.
- Flask-Migrate: Tegeleb andmebaasi skeemi migratsioonidega.
- Flask-WTF: Lihtsustab veebivormidega töötamist, pakkudes valideerimist ja CSRF-kaitset.
- Flask-Login: Haldab kasutajaseanssi, tegeledes sisselogimise, väljalogimise ja kasutajate meelespidamisega.
- Flask-Bcrypt: Pakub tugevaid paroolide räsimise võimekusi.
- python-dotenv: Haldab keskkonnamuutujaid seadistamiseks.
Installige need kõik ühe käsuga:
pip install Flask Flask-SQLAlchemy Flask-Migrate Flask-WTF Flask-Login Flask-Bcrypt python-dotenv
1. osa: Vundament – Projekti Struktuur ja Andmebaasi Mudel
Hästi organiseeritud projekti on lihtsam hooldada, skaleerida ja mõista. Kasutame levinud Flasi rakenduse tehase (application factory) mustrit.
Skaleeritava Projekti Struktuuri Kujundamine
Looge järgmine kausta- ja failistruktuur oma `flask-auth-project` kausta sisse:
/flask-auth-project
|-- /app
| |-- /static
| |-- /templates
| | |-- base.html
| | |-- index.html
| | |-- login.html
| | |-- register.html
| | |-- dashboard.html
| |-- __init__.py
| |-- models.py
| |-- forms.py
| |-- routes.py
|-- .env
|-- config.py
|-- run.py
- /app: Põhipakett, mis sisaldab meie rakenduse loogikat.
- /templates: Hoiab meie HTML-faile.
- __init__.py: Initsialiseerib meie Flasi rakenduse (rakenduse tehas).
- models.py: Määratleb meie andmebaasi tabelid (nt Kasutaja mudel).
- forms.py: Määratleb meie registreerimis- ja sisselogimisvormid Flask-WTF abil.
- routes.py: Sisaldab meie vaatefunktsioone (loogika erinevate URL-ide jaoks).
- config.py: Hoiab rakenduse konfiguratsiooniseadeid.
- run.py: Põhiskript veebiserveri käivitamiseks.
- .env: Fail keskkonnamuutujate, nagu salajaste võtmete, hoidmiseks (seda faili EI TOHI versioonihaldusesse lisada).
Flasi Rakenduse Konfigureerimine
Täidame nüüd oma konfiguratsioonifailid.
.env fail:
Looge see fail oma projekti juurkataloogi. Siin hoiame tundlikku teavet.
SECRET_KEY='a-very-strong-and-long-random-secret-key'
DATABASE_URL='sqlite:///site.db'
TÄHTIS: Asendage `SECRET_KEY` väärtus omaenda pika, juhusliku ja ettearvamatu stringiga. See võti on kasutajaseansside turvamiseks ülioluline.
config.py fail:
See fail loeb konfiguratsiooni meie `.env` failist.
import os
from dotenv import load_dotenv
basedir = os.path.abspath(os.path.dirname(__file__))
load_dotenv(os.path.join(basedir, '.env'))
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY')
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
Kasutajamudeli Loomine Flask-SQLAlchemy'ga
Kasutaja mudel on meie autentimissüsteemi süda. See määratleb meie andmebaasi `users` tabeli struktuuri.
app/models.py:
from flask_login import UserMixin
from . import db, login_manager
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(128), nullable=False)
def __repr__(self):
return f''
Vaatame selle lähemalt üle:
- `UserMixin`: See on klass `Flask-Login` laiendusest, mis sisaldab ĂĽldisi implementatsioone meetoditele nagu `is_authenticated`, `is_active` jne, mida meie Kasutaja mudel vajab.
- `@login_manager.user_loader`: See funktsioon on `Flask-Login` jaoks nõutav. Seda kasutatakse kasutajaobjekti uuesti laadimiseks seansis talletatud kasutaja ID põhjal. Flask-Login kutsub seda funktsiooni iga sisselogitud kasutaja päringu korral.
- `password_hash`: Pange tähele, et me EI salvesta parooli otse. Me salvestame `password_hash`'i ehk parooli räsi. See on üks kriitilisemaid turvaprintsiipe autentimisel. Avatekstina paroolide salvestamine on massiivne turvaauk. Kui teie andmebaas kunagi kompromiteeritakse, on ründajatel iga kasutaja parool. Räsi salvestades muudate algsete paroolide kättesaamise arvutuslikult teostamatuks.
Rakenduse Initsialiseerimine
Nüüd seome kõik oma rakenduse tehases kokku.
app/__init__.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from config import Config
db = SQLAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager()
login_manager.login_view = 'main.login' # Leht, kuhu sisselogimata kasutajad suunatakse
login_manager.login_message_category = 'info' # Bootstrap klass teadete jaoks
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
bcrypt.init_app(app)
login_manager.init_app(app)
from .routes import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
run.py:
from app import create_app, db
from app.models import User
app = create_app()
@app.shell_context_processor
def make_shell_context():
return {'db': db, 'User': User}
if __name__ == '__main__':
app.run(debug=True)
Enne rakenduse käivitamist peame looma andmebaasi. Käivitage oma aktiveeritud virtuaalkeskkonnas terminalis järgmised käsud:
flask shell
>>> from app import db
>>> db.create_all()
>>> exit()
See loob teie juurkataloogi faili `site.db`, mis sisaldab meie defineeritud `user` tabelit.
2. osa: Põhilise Autentimisloogika Ehitamine
Nüüd, kui vundament on paigas, saame ehitada kasutajale suunatud osad: registreerimis- ja sisselogimisvormid ning neid töötlevad marsruudid.
Kasutajate Registreerimine: Uute Kasutajate Turvaline Lisamine
Esmalt defineerime vormi, kasutades Flask-WTF-i.
app/forms.py:
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
from .models import User
class RegistrationForm(FlaskForm):
username = StringField('Kasutajanimi',
validators=[DataRequired(), Length(min=2, max=20)])
email = StringField('E-post',
validators=[DataRequired(), Email()])
password = PasswordField('Parool', validators=[DataRequired()])
confirm_password = PasswordField('Kinnita parool',
validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Registreeru')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user:
raise ValidationError('See kasutajanimi on juba võetud. Palun valige teine.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user:
raise ValidationError('See e-posti aadress on juba registreeritud. Palun valige teine.')
class LoginForm(FlaskForm):
email = StringField('E-post',
validators=[DataRequired(), Email()])
password = PasswordField('Parool', validators=[DataRequired()])
remember = BooleanField('Jäta mind meelde')
submit = SubmitField('Logi sisse')
Pange tähele kohandatud validaatoreid `validate_username` ja `validate_email`. Flask-WTF kutsub automaatselt välja kõik meetodid, mis järgivad mustrit `validate_
Järgmisena loome marsruudi registreerimise käsitlemiseks.
app/routes.py:
from flask import Blueprint, render_template, url_for, flash, redirect, request
from .forms import RegistrationForm, LoginForm
from .models import User
from . import db, bcrypt
from flask_login import login_user, current_user, logout_user, login_required
main = Blueprint('main', __name__)
@main.route('/')
@main.route('/index')
def index():
return render_template('index.html')
@main.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('main.index'))
form = RegistrationForm()
if form.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user = User(username=form.username.data, email=form.email.data, password_hash=hashed_password)
db.session.add(user)
db.session.commit()
flash('Teie konto on loodud! Saate nĂĽĂĽd sisse logida', 'success')
return redirect(url_for('main.login'))
return render_template('register.html', title='Registreeru', form=form)
Paroolide Räsimine Flask-Bcrypt'iga
Kõige olulisem rida ülaltoodud koodis on:
hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
Bcrypt on kaasaegne, adaptiivne räsialgoritm. See võtab kasutaja parooli ja teostab sellel keeruka, arvutuslikult kuluka ühesuunalise teisenduse. Samuti lisab see igale paroolile juhusliku "soola" (salt), et vältida vikerkaare-tabeli rünnakuid (rainbow table attacks). See tähendab, et isegi kui kahel kasutajal on sama parool, on nende salvestatud räsid täiesti erinevad. Tulemuseks olev räsi on see, mida me andmebaasis hoiame. Selle protsessi ümberpööramine algse parooli saamiseks on praktiliselt võimatu.
Kasutaja Sisselogimine: Olemasolevate Kasutajate Autentimine
NĂĽĂĽd lisame sisselogimise marsruudi meie `app/routes.py` faili.
app/routes.py (lisage see marsruut):
@main.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('main.index'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and bcrypt.check_password_hash(user.password_hash, form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
return redirect(next_page) if next_page else redirect(url_for('main.index'))
else:
flash('Sisselogimine ebaõnnestus. Palun kontrollige e-posti ja parooli', 'danger')
return render_template('login.html', title='Logi sisse', form=form)
Peamised sammud siin on:
- Leia kasutaja: Teeme andmebaasist päringu kasutaja leidmiseks sisestatud e-posti aadressi alusel.
- Kontrolli parooli: See on ülioluline kontroll: `bcrypt.check_password_hash(user.password_hash, form.password.data)`. See funktsioon võtab meie andmebaasist salvestatud räsi ja kasutaja äsja sisestatud avatekstina parooli. See räsib uuesti sisestatud parooli, kasutades sama soola (mis on salvestatud räsi enda osana), ja võrdleb tulemusi. See tagastab `True` ainult siis, kui need ühtivad. See võimaldab meil parooli kontrollida, ilma et peaksime kunagi salvestatud räsi dekrüpteerima.
- Halda seanssi: Kui parool on õige, kutsume välja funktsiooni `login_user(user, remember=form.remember.data)`. See `Flask-Login` funktsioon registreerib kasutaja sisselogituks, salvestades tema ID kasutajaseanssi (turvaline, serveripoolne küpsis). `remember` argument tegeleb "Jäta mind meelde" funktsionaalsusega.
Kasutaja Väljalogimine: Seansi Turvaline Lõpetamine
Väljalogimine on lihtne. Meil on vaja vaid marsruuti, mis kutsub välja `Flask-Login` laienduse funktsiooni `logout_user`.
app/routes.py (lisage see marsruut):
@main.route('/logout')
def logout():
logout_user()
return redirect(url_for('main.index'))
See funktsioon kustutab kasutaja ID seansist, logides ta tõhusalt välja.
3. osa: Marsruutide Kaitsmine ja Kasutajaseansside Haldamine
Nüüd, kui kasutajad saavad sisse ja välja logida, peame nende autenditud olekut ära kasutama.
Sisu Kaitsmine `@login_required` Dekoraatoriga
Paljud lehed, nagu kasutaja töölaud või konto seaded, peaksid olema kättesaadavad ainult sisselogitud kasutajatele. `Flask-Login` muudab selle `@login_required` dekoraatori abil uskumatult lihtsaks.
Loome kaitstud töölaua marsruudi.
app/routes.py (lisage see marsruut):
@main.route('/dashboard')
@login_required
def dashboard():
return render_template('dashboard.html', title='Töölaud')
See ongi kõik! Kui sisselogimata kasutaja üritab külastada `/dashboard` lehte, peatab `Flask-Login` automaatselt päringu ja suunab ta sisselogimislehele (mille me konfigureerisime `app/__init__.py` failis reaga `login_manager.login_view = 'main.login'`). Pärast edukat sisselogimist suunab see ta arukalt tagasi töölaua lehele, kuhu ta algselt püüdis pääseda.
Praeguse Kasutaja Teabele Juurdepääs
Teie marsruutides ja mallides pakub `Flask-Login` maagilist proksi-objekti nimega `current_user`. See objekt esindab kasutajat, kes on praeguse päringu jaoks sisse logitud. Kui ükski kasutaja pole sisse logitud, on see anonüümne kasutajaobjekt, mille puhul `current_user.is_authenticated` on `False`.
Saate seda kasutada oma Pythoni koodis:
# Marsruudis
if current_user.is_authenticated:
print(f'Tere, {current_user.username}!')
Ja saate seda kasutada ka otse oma Jinja2 mallides:
<!-- Mallis nagu base.html -->
{% if current_user.is_authenticated %}
<a href="{{ url_for('main.dashboard') }}">Töölaud</a>
<a href="{{ url_for('main.logout') }}">Logi välja</a>
{% else %}
<a href="{{ url_for('main.login') }}">Logi sisse</a>
<a href="{{ url_for('main.register') }}">Registreeru</a>
{% endif %}
See võimaldab teil dünaamiliselt muuta navigeerimisriba või muid kasutajaliidese osi vastavalt kasutaja sisselogimisstaatusele.
HTML Mallid
Täielikkuse huvides on siin mõned põhilised mallid, mille saate paigutada `app/templates` kausta. Need kasutavad lihtsat HTML-i, kuid neid saab hõlpsasti integreerida raamistikega nagu Bootstrap või Tailwind CSS.
base.html:
<!DOCTYPE html>
<html lang="et">
<head>
<meta charset="UTF-8">
<title>{{ title }} - Flasi Autentimisrakendus</title>
</head>
<body>
<nav>
<a href="{{ url_for('main.index') }}">Avaleht</a>
{% if current_user.is_authenticated %}
<a href="{{ url_for('main.dashboard') }}">Töölaud</a>
<a href="{{ url_for('main.logout') }}">Logi välja</a>
{% else %}
<a href="{{ url_for('main.login') }}">Logi sisse</a>
<a href="{{ url_for('main.register') }}">Registreeru</a>
{% endif %}
</nav>
<hr>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</body>
</html>
register.html / login.html (näide registreerimisvormiga):
{% extends "base.html" %}
{% block content %}
<div>
<form method="POST" action="">
{{ form.hidden_tag() }}
<fieldset>
<legend>Liitu täna</legend>
<div>
{{ form.username.label }}
{{ form.username() }}
</div>
<div>
{{ form.email.label }}
{{ form.email() }}
</div>
<div>
{{ form.password.label }}
{{ form.password() }}
</div>
<div>
{{ form.confirm_password.label }}
{{ form.confirm_password() }}
</div>
</fieldset>
<div>
{{ form.submit() }}
</div>
</form>
</div>
{% endblock content %}
4. osa: Täiustatud Teemad ja Turvalisuse Parimad Praktikad
Süsteem, mille oleme ehitanud, on tugev, kuid tootmiskvaliteediga rakendus nõuab enamat. Siin on olulised järgmised sammud ja turvakaalutlused.
1. Parooli Lähtestamise Funktsionaalsus
Kasutajad unustavad paratamatult oma paroole. Turvaline parooli lähtestamise protsess on ülioluline. Standardne ja turvaline protsess on järgmine:
- Kasutaja sisestab oma e-posti aadressi lehel "Unustasid parooli?".
- Rakendus genereerib turvalise, ĂĽhekordse ja ajatundliku loa (token). `itsdangerous` teek (mis installitakse koos Flaskiga) on selleks ideaalne.
- Rakendus saadab kasutajale e-kirja, mis sisaldab linki selle loaga.
- Kui kasutaja lingile klõpsab, valideerib rakendus loa (kontrollides selle kehtivust ja aegumist).
- Kui luba on kehtiv, esitatakse kasutajale vorm uue parooli sisestamiseks ja kinnitamiseks.
Ärge kunagi saatke kasutajale e-kirjaga tema vana parooli ega uut avatekstina parooli.
2. E-posti Kinnitus Registreerimisel
Et vältida kasutajate registreerumist võltsitud e-posti aadressidega ja tagada, et saate nendega ühendust võtta, peaksite rakendama e-posti kinnitamise sammu. Protsess on väga sarnane parooli lähtestamisega: genereerige luba, saatke e-kirjaga kinnituslink ja looge marsruut, mis valideerib loa ja märgib kasutaja konto andmebaasis `kinnitatuks`.
3. Päringute Piiramine Jõurünnakute Vältimiseks
Jõurünnak (brute-force attack) on see, kui ründaja proovib korduvalt erinevaid paroole sisselogimisvormil. Selle leevendamiseks peaksite rakendama päringute piiramist (rate limiting). See piirab sisselogimiskatsete arvu, mida üks IP-aadress saab teatud aja jooksul teha (nt 5 ebaõnnestunud katset minutis). `Flask-Limiter` laiendus on selleks suurepärane tööriist.
4. Keskkonnamuutujate Kasutamine Kõikide Saladuste Jaoks
Oleme seda juba teinud oma `SECRET_KEY` ja `DATABASE_URL` jaoks, mis on suurepärane. See on turvalisuse ja kaasaskantavuse seisukohast kriitilise tähtsusega praktika. Ärge kunagi lisage oma `.env` faili ega ühtegi faili, mis sisaldab kõvakodeeritud mandaate (nagu API-võtmed või andmebaasi paroolid), avalikku versioonihaldussüsteemi nagu GitHub. Kasutage nende välistamiseks alati `.gitignore` faili.
5. Saidiväliste Päringute Võltsimise (CSRF) Kaitse
Hea uudis! Kasutades `Flask-WTF` ja lisades oma vormidesse `{{ form.hidden_tag() }}`, oleme juba CSRF-kaitse aktiveerinud. See peidetud silt genereerib iga vormi esitamise jaoks unikaalse loa, tagades, et päring tuleb teie tegelikult saidilt, mitte pahatahtlikust välisest allikast, mis üritab teie kasutajaid petta.
Kokkuvõte: Teie Järgmised Sammud Flasi Autentimisel
Palju õnne! Olete edukalt ehitanud täieliku ja turvalise kasutaja autentimissüsteemi Flaskis. Oleme käsitlenud kogu elutsüklit: skaleeritava projekti seadistamine, andmebaasimudeli loomine, kasutajate turvaline registreerimine paroolide räsimisega, kasutajate autentimine, seansside haldamine Flask-Loginiga ja marsruutide kaitsmine.
Teil on nüüd tugev vundament, mille saate enesekindlalt integreerida mis tahes Flasi projekti. Pidage meeles, et turvalisus on pidev protsess, mitte ühekordne seadistus. Põhimõtted, mida oleme arutanud – eriti paroolide räsimine ja salajaste võtmete kaitsmine – on iga kasutajaandmeid käsitleva rakenduse jaoks vältimatud.
Siit saate edasi uurida veelgi arenenumaid autentimisteemasid, et oma rakendust veelgi täiustada:
- Rollipõhine Juurdepääsukontroll (RBAC): Lisage oma Kasutaja mudelile `rolli` väli, et anda tavakasutajatele ja administraatoritele erinevaid õigusi.
- OAuth'i Integreerimine: Lubage kasutajatel sisse logida kolmandate osapoolte teenuste, nagu Google, GitHub või Facebook, abil.
- Kahefaktoriline Autentimine (2FA): Lisage täiendav turvakiht, nõudes koodi autentimisrakendusest või SMS-sõnumist.
Autentimise aluste omandamisega olete teinud olulise sammu edasi oma teekonnal professionaalse veebiarendajana. Head kodeerimist!